/*
============================================================================
 Name        : TCPSocketEngine.cpp
 Author      : 
 Version     :
 Copyright   : Your copyright notice
 Description : CTCPSocketEngine implementation
============================================================================
*/
#include "TCPSocket.h" // for Panic();
#include "TCPSocketEngine.h"
#include "iapManager.h"
#include "CommDbConnPref.h"

const TInt KTimeout = 30; // second
// Two-phased constructor.
CTCPSocketEngine* CTCPSocketEngine::NewL(MTcpObserver& aObserver)
{
	CTCPSocketEngine* self = new (ELeave) CTCPSocketEngine( aObserver );
	CleanupStack::PushL( self );
	self->ConstructL();
	CleanupStack::Pop();
	return self;
}

CTCPSocketEngine::CTCPSocketEngine(MTcpObserver& aObserver):
CActive(CActive::EPriorityStandard), iObserver(aObserver)
{
	CActiveScheduler* scheduler=CActiveScheduler::Current();
	CActiveScheduler::Add(this);
}

void CTCPSocketEngine::ConstructL()
{ // Open a session to Socket Server
	User::LeaveIfError(iSocketServ.Connect());

	iTimer = CTCPSocketTimer::NewL(*this);

	iSender = CTCPSocketSender::NewL(*this, iSocket);
	iReceiver = new(ELeave) CTCPSocketReceiver(*this, iSocket);

	iState=EStateIdle;
	iConntectRetry = 0;
	
	iSocketStatus = EFalse; //初始化值为  false 
	iHandShakeComplete = EFalse;
	iSSLSocket  = NULL;
	
	iTmpMsg = NULL;
	

}

CTCPSocketEngine::~CTCPSocketEngine()
{
	delete iTimer;
	delete iSender;
	delete iReceiver;
	
	if(iSSLSocket)
	{
		delete iSSLSocket;
	
	}
	Cancel();
	iSocket.Close();
	iListenSocket.Close();
	iConnection.Close();
	iSocketServ.Close();	
}

void CTCPSocketEngine::RunL()
{
	TInt err = iStatus.Int();
	switch(iState)
	{
	case EStateCreateIapConnection:
			{
			if(err==KErrNone)
				{
			// iap 建立成功，进行下一步连接
			this->ResolveDomain();
				}
			else
				{
					 if(iConntectRetry++ <= 2)
				     {
						 this->iObserver.GetIap(iIAP);	
						
						 this->CreateIApConnection();
			         }

				}
			break;
			}
	case EStateDomainResolved:
		{
			if(err==KErrNone)
			{
			// 域名解析成功，开始连接
			iResolver.Close();
			// DNS look up successful
			TNameRecord record;
			record = iNameEntry();
			// And connect to the IP address
			iAddr.SetAddress(TInetAddr::Cast( record.iAddr ).Address());			
			TBuf<100> b;
			iAddr.Output(b);			
			iAddr.SetPort(iPort);
			this->DoConnect();
			}
		else
			{
			iResolver.Cancel();
			iResolver.Close();
			iSocket.Close();
			iState = EStateIdle;
			this->iObserver.OnConnectL(err);
			}
		break;
		}
	
	case EStateConnecting:
		{
			iTimer->Cancel();
			if (err == KErrNone)
			{
				// Connection completed successfully
				iState = EStateConnected;
				ReceiveL();
			}
			else
			{
				iSocket.Close();
				iState = EStateIdle;
			}
			iObserver.OnConnectL(err);
			break;
		}	
	default:
		{
			// unreachable
			break;
		}
	}
}


// New functions
CTCPSocketEngine::TState CTCPSocketEngine::State()
{
	return iState;
}
void CTCPSocketEngine::CreateIApConnection()
	{
		iState = EStateCreateIapConnection;		
		
		TCommDbConnPref connectPref;
		// setup preferences 
		connectPref.SetBearerSet(ECommDbBearerWcdma | ECommDbBearerGPRS
				| ECommDbBearerWLAN | ECommDbBearerCdma2000);
		connectPref.SetDialogPreference(ECommDbDialogPrefDoNotPrompt);
		connectPref.SetIapId(iIAP);
		connectPref.SetDirection(ECommDbConnectionDirectionOutgoing);

		User::LeaveIfError(iConnection.Open(iSocketServ));
		iConnection.Start(connectPref, iStatus);
		SetActive();
	}
void CTCPSocketEngine::ResolveDomain()
	{
		if(iAddr.Input(iServer) == KErrNone) 
		{
			// 不用解析，直接连接
			DoConnect();
		} 
		else 
		{
			User::LeaveIfError(iResolver.Open(iSocketServ, KAfInet, KProtocolInetUdp, iConnection));
			iResolver.GetByName(iServer, iNameEntry, iStatus);		
	
			iState=EStateDomainResolved;
			SetActive();
		}
	}
void CTCPSocketEngine::ConnectL(const TDesC& aAddr, TUint aPort)
{
	if(iState!=EStateIdle)
		{
		iSocket.CancelConnect();
		iState=EStateIdle;
		}
	iServer.Copy(aAddr);
	this->iPort=aPort;
	
	IapManager::AutoGetIap(iIAP);
	CreateIApConnection();	
}
void CTCPSocketEngine::DoConnect()
	{	
		iState = EStateConnecting;
		// Open a TCP socket
		User::LeaveIfError(iSocket.Open(iSocketServ, KAfInet, KSockStream, KProtocolInetTcp,iConnection));
	
		// Initiate socket connection
		iSocket.Connect(iAddr, iStatus);
		
		SetActive();
		// Start a timeout timer
		iTimer->Start(KTimeout);		

	}
void CTCPSocketEngine::Disconnect()
{
	__ASSERT_DEBUG(iState==EStateConnected, Panic(ETCPSocketPanicFailToDisconnect));

	// cancel all outstanding operations
	// since we are connected, the only possibilities are read and write
	iReceiver->Cancel();
	iSender->Cancel();
	iSocket.Close();

	iState = EStateIdle;
}

void CTCPSocketEngine::SendL(const TDesC8& aMsg)
{
	__ASSERT_DEBUG(iState==EStateConnected, Panic(ETCPSocketPanicFailToSend));

	
	if(iSocketStatus)
	{
		if(!iHandShakeComplete)
		{
			if(iTmpMsg)
			{
				delete iTmpMsg;
				iTmpMsg = NULL;
			}
			
			iTmpMsg = aMsg.Alloc();
		}
		else
		{
			iSSLSocket->SendSSL(aMsg);
		}
	}
	else
	{
		iSender->Send(aMsg);
	}
	
}

void CTCPSocketEngine::ReceiveL()
{
	__ASSERT_DEBUG(iState==EStateConnected, Panic(ETCPSocketPanicFailToReceive));

	if(iSocketStatus)
	{
		if(iHandShakeComplete)
		{
			iSSLSocket->RevSSL();
		}
	}
	else
	{
		iReceiver->Receive();
	}
	
}

// Functions from CActive
void CTCPSocketEngine::DoCancel()
{
	switch(iState)
	{
	case EStateConnecting:
		{
			iTimer->Cancel();
			iSocket.CancelConnect();
			break;
		}
	default:
		{
			// unreachable
			break;
		}
	}
	iState = EStateIdle;
}


// Functions from CTcpSocketTimer::MTimerObserver
void CTCPSocketEngine::OnTimerL(TInt aError)
{
	Cancel();
	TInt err = (aError==KErrNone)?KErrTimedOut:aError;
	iObserver.OnConnectL(err);
}

// Functions from CTcpSocketSender::MObserver
void CTCPSocketEngine::OnSendL(const TDesC8& aMsg, TInt aError)
{
	
	iObserver.OnSendL(aMsg, aError);
}

// Functions from CTcpSocketReceiver::MObserver
void CTCPSocketEngine::OnReceiveL(const TDesC8& aData, TInt aError)
{	
	if(aError==KErrNone)
	{	
		iObserver.OnReceiveL(aData, aError);
		if(iState==EStateConnected)
			ReceiveL();
	}
	else
	{
		Disconnect();	
		iObserver.OnReceiveL(aData, aError);
	}
	
}

void CTCPSocketEngine::StartSSL()
{
	if(!iSocketStatus)
	{

		iSocketStatus = ETrue;

		
		if(iSSLSocket)
		{
			delete iSSLSocket;
			iSSLSocket = NULL;
		
		}

		iSSLSocket = CTCPSocketSSL::NewL(*this,iSocket);
		
		iSender->Cancel();
		iReceiver->Cancel();
	}

}

void CTCPSocketEngine::StopSSL()
{
	if(iSocketStatus)
	{
		iSocketStatus = EFalse;

		
		if(iSSLSocket)
		{
			delete iSSLSocket;
			iSSLSocket = NULL;
		}
		
		iHandShakeComplete = EFalse;
	}

}


void CTCPSocketEngine::OnSendSSL(const TDesC8& aMsg, TInt aError) 
{
	
	iObserver.OnSendL(aMsg, aError);
}

void CTCPSocketEngine::OnHandComplete(TInt aError)
{
	
	if(aError == KErrNone)
	{
	
		if(iSocketStatus)
		{
			iHandShakeComplete = ETrue;
			
			if(iTmpMsg)
			{
				iSSLSocket->SendSSL(*iTmpMsg);
				
				delete iTmpMsg;
				iTmpMsg = NULL;
			}
			
			
			iObserver.SSLHandShakeComplete(aError);
		}

	}
	else
	{
		iObserver.SSLHandShakeComplete(aError);
	}
	
}

void CTCPSocketEngine::OnRevSSL(const TDesC8& aData, TInt aError)
{
	if(aError==KErrNone)
	{	
		iObserver.OnReceiveL(aData, aError);
		if(iState==EStateConnected)
			ReceiveL();
	}
	else
	{
		Disconnect();	
		iObserver.OnReceiveL(aData, aError);
	}

}
